<?php

namespace app\api\controller;

use app\common\controller\Api;
use think\Log;
use think\Request;

/**
 * 豆包AI流式输出接口
 */
class BeanbunsStream extends Api
{
    protected $noNeedLogin = ['*'];
    protected $noNeedRight = ['*'];

    private $config;
    private $apiKey;

    public function _initialize()
    {
        parent::_initialize();
        $this->config = config('doubao');
        $this->apiKey = $this->config['api_key'];
    }
       

    /**
     * 流式文本对话 - 优化版本（纯文字输出）
     * GET/POST /api/beanbuns_stream/chat
     * 参数: question=你好&temperature=0.7&max_tokens=4000&stream_mode=char
     * stream_mode: char(逐字符) | word(逐词) | chunk(分块) | complete(完整)
     * 注意：此接口输出纯文字，不处理Markdown格式（如###、**等）和数学公式
     */
    public function chat(Request $request)
    {
        try {
            // 获取参数
            $question = trim($request->param('question', ''));
            $temperature = (float)$request->param('temperature', 0.7);
            $maxTokens = (int)$request->param('max_tokens', 4000);
            $model = $request->param('model', 'doubao-1.5-pro-32k-250115');
            $streamMode = $request->param('stream_mode', 'char'); // 新增流式模式参数
            
            // 参数验证
            if (empty($question)) {
                $this->streamError('问题内容不能为空');
                return;
            }
            
            if (mb_strlen($question, 'UTF-8') > 10000) {
                $this->streamError('问题内容过长，请控制在10000字符以内');
                return;
            }
            
            if ($temperature < 0 || $temperature > 2) {
                $this->streamError('temperature参数必须在0-2之间');
                return;
            }
            
            if ($maxTokens < 1 || $maxTokens > 8000) {
                $this->streamError('max_tokens参数必须在1-8000之间');
                return;
            }
            
            // 验证流式模式
            $validModes = ['char', 'word', 'chunk', 'complete'];
            if (!in_array($streamMode, $validModes)) {
                $this->streamError('stream_mode参数必须是: ' . implode(', ', $validModes));
                return;
            }

            $data = [
                'temperature' => $temperature,
                'max_tokens' => $maxTokens,
                'model' => $model,
                'stream_mode' => $streamMode
            ];
            
            // 启动流式对话
            $this->startStreamWithParams($question, '', $data);
            // 重要：确保流式输出完成后才结束请求
            exit; // 添加exit确保脚本终止
        } catch (\Exception $e) {
            error_log('豆包流式聊天错误: ' . $e->getMessage());
            $this->streamError('系统错误: ' . $e->getMessage());
        }
    }
    
    /**
     * 流式图文对话 - 优化版本
     * GET/POST /api/beanbuns_stream/image
     * 参数: question=描述图片&image=图片URL或base64&temperature=0.7
     */
    public function image(Request $request)
    {
        try {
            $question = trim($request->param('question', ''));
            $image = trim($request->param('image', ''));
            $temperature = (float)$request->param('temperature', 0.7);
            $maxTokens = (int)$request->param('max_tokens', 4000);
            
            if (empty($question) && empty($image)) {
                $this->streamError('问题或图片至少需要一个');
                return;
            }
            $this->startStreamWithParams($question, $image, [
                'temperature' => $temperature,
                'max_tokens' => $maxTokens,
                // 'model' => 'doubao-1-5-thinking-vision-pro-250428'
            ]);
            
        } catch (\Exception $e) {
            error_log('豆包流式图文错误: ' . $e->getMessage());
            $this->streamError('系统错误: ' . $e->getMessage());
        }
    }
    
    private $streamMode = 'char'; // 默认流式模式
    
    /**
     * 带参数的流式对话
     */
    private function startStreamWithParams($question, $image = '', $params = [])
    {

        // 设置流式模式
        $this->streamMode = $params['stream_mode'] ?? 'char';
        // 设置优化的SSE响应头
        $this->setOptimizedHeaders();
      
        try {
            // 构建请求数据
            $requestData = $this->buildRequestDataWithParams($question, $image, $params);
            
            // 验证请求数据
            $this->validateRequestData($requestData);
            
            // 发送开始事件
            $this->sendEvent('start', '开始生成回答...');
            
            // 执行流式请求
            $this->executeRequest($requestData);
            
        } catch (\Exception $e) {
            error_log('豆包流式请求错误: ' . $e->getMessage());
            $this->sendEvent('error', '系统错误: ' . $e->getMessage());
        }
        
        $this->sendEvent('end', '对话结束');
        exit;
    }
    
    /**
     * 构建带参数的请求数据
     */
    private function buildRequestDataWithParams($question, $image = '', $params = [])
    {
        $temperature = $params['temperature'] ?? 0.7;
        $maxTokens = $params['max_tokens'] ?? 4000;
        $model = $params['model'] ?? 'doubao-1.5-pro-32k-250115';
        
        if (empty($image)) {
            // 纯文本对话
            return [
                'model' => $model,
                'messages' => [[
                    'role' => 'user', 
                    'content' => $question
                ]],
                'stream' => true,
                'temperature' => $temperature,
                'max_tokens' => $maxTokens,
                'top_p' => 0.9,
                'frequency_penalty' => 0.1,
                'presence_penalty' => 0.1
            ];
        } else {
            // 图文对话
            $content = [];
            if ($question) {
                $content[] = ['type' => 'text', 'text' => $question];
            }
            $content[] = [
                'type' => 'image_url',
                'image_url' => ['url' => $this->processImage($image)]
            ];
            
            return [
                'model' => 'doubao-1-5-thinking-vision-pro-250428',
                'messages' => [[
                    'role' => 'user', 
                    'content' => $content
                ]],
                'stream' => true,
                'temperature' => $temperature,
                'max_tokens' => $maxTokens
            ];
        }
    }
    
    /**
     * 设置优化的响应头 - 针对Nginx + PHP-FPM环境优化
     */
    private function setOptimizedHeaders()
    {
        
        // 在任何输出之前设置响应头
        header('Content-Type: text/event-stream; charset=utf-8');
        header('Cache-Control: no-cache, no-store, must-revalidate');
        header('Pragma: no-cache');
        header('Expires: 0');
        header('Connection: keep-alive');
        header('Access-Control-Allow-Origin: *');
        header('X-Accel-Buffering: no'); // 禁用Nginx缓冲
        
        // 强制清除所有输出缓冲区 - 重要修复
        while (ob_get_level() > 0) {
            ob_end_clean();
        }
        
        // 禁用PHP输出缓冲
        ini_set('output_buffering', 'off');
        ini_set('zlib.output_compression', 'off');
        ini_set('implicit_flush', '1');
        
        // 启用自动刷新
        ob_implicit_flush(true);
        
        // 设置无限制执行时间
        set_time_limit(0);
        
        // 立即刷新输出
        if (function_exists('apache_setenv')) {
            apache_setenv('no-gzip', '1');
        }
        
        // 发送初始数据，确保连接建立
        echo "retry: 1000\n\n";
        if (ob_get_level() > 0) {
            ob_flush();
        }
        
        flush();
        
        // 注意：不要在这里调用 fastcgi_finish_request()，它会立即结束请求
        // fastcgi_finish_request() 应该只在流式输出完全结束后调用
    }
    
    /**
     * 构建请求数据
     */
    private function buildRequestData($question, $image = '')
    {
        if (empty($image)) {
            // 纯文本对话
            return [
                'model' => 'doubao-1.5-pro-32k-250115',
                'messages' => [[
                    'role' => 'user', 
                    'content' => $question
                ]],
                'stream' => true,
                'temperature' => 0.7,
                'max_tokens' => 4000,  // 增加最大token数
                'top_p' => 0.9,
                'frequency_penalty' => 0.1,
                'presence_penalty' => 0.1
            ];
        } else {
            // 图文对话
            $content = [];
            if ($question) {
                $content[] = ['type' => 'text', 'text' => $question];
            }
            $content[] = [
                'type' => 'image_url',
                'image_url' => ['url' => $this->processImage($image)]
            ];
            
            return [
                'model' => 'doubao-1-5-thinking-vision-pro-250428',
                'messages' => [[
                    'role' => 'user', 
                    'content' => $content
                ]],
                'stream' => true,
                'temperature' => 0.7,
                'max_tokens' => 4000
            ];
        }
    }
    
    /**
     * 验证请求数据
     */
    private function validateRequestData($requestData)
    {
        if (empty($requestData['messages'])) {
            throw new \Exception('消息内容不能为空');
        }
        
        if (empty($requestData['model'])) {
            throw new \Exception('模型参数不能为空');
        }
        
        // 检查消息长度
        $totalLength = 0;
        foreach ($requestData['messages'] as $message) {
            if (isset($message['content']) && is_string($message['content'])) {
                $totalLength += mb_strlen($message['content'], 'UTF-8');
            }
        }
        
        if ($totalLength > 50000) { // 50k字符限制
            throw new \Exception('消息内容过长，请减少内容后重试');
        }
    }
    
    /**
     * 执行流式API请求 - 优化版本
     */
    private function executeRequest($data)
    {
        // 记录请求开始
        error_log('豆包API请求开始: ' . json_encode([
            'url' => $this->config['chat_api_url'],
            'model' => $data['model'] ?? 'unknown',
            'stream_mode' => $this->streamMode
        ]));
        
        $ch = curl_init();
        
        // 豆包API优化配置
        curl_setopt_array($ch, [
            CURLOPT_URL => $this->config['chat_api_url'],
            CURLOPT_RETURNTRANSFER => false,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => json_encode($data, JSON_UNESCAPED_UNICODE),
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json; charset=utf-8',
                'Authorization: Bearer ' . $this->apiKey,
                'Accept: text/event-stream',
                'Cache-Control: no-cache',
                'Connection: keep-alive'
            ],
            CURLOPT_WRITEFUNCTION => [$this, 'handleStreamData'],
            CURLOPT_TIMEOUT => 300,  // 5分钟超时
            CURLOPT_CONNECTTIMEOUT => 30,  // 连接超时30秒
            CURLOPT_SSL_VERIFYPEER => false,  // 跳过SSL证书验证
            CURLOPT_SSL_VERIFYHOST => false,  // 跳过主机验证
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_MAXREDIRS => 3,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_USERAGENT => 'BeanbunStream/1.0 PHP/' . PHP_VERSION,
            // 流式优化
            CURLOPT_BUFFERSIZE => 1024,  // 1KB缓冲区
            CURLOPT_TCP_NODELAY => true,  // 禁用Nagle算法，提高实时性
            CURLOPT_LOW_SPEED_LIMIT => 1,  // 最低速度1字节/秒
            CURLOPT_LOW_SPEED_TIME => 60   // 60秒内速度低于限制则超时
        ]);
        
        $result = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        $errno = curl_errno($ch);
        
        // 记录请求结果
        error_log('豆包API请求结束: ' . json_encode([
            'http_code' => $httpCode,
            'curl_error' => $error,
            'curl_errno' => $errno,
            'result' => $result !== false ? 'success' : 'failed'
        ]));
        
        // 确保发送结束事件
        $this->sendEvent('end', '对话结束');
        
        if ($result === false || !empty($error)) {
            error_log('豆包API请求错误: ' . ($error ?: '未知错误') . ' (errno: ' . $errno . ')');
        } elseif ($httpCode !== 200) {
            $errorMsg = $this->getHttpErrorMessage($httpCode);
            error_log('豆包API HTTP错误: ' . $httpCode . ' - ' . $errorMsg);
        }
        curl_close($ch);
    }
    
    /**
     * 处理流式数据 - 优化版本
     */
    public function handleStreamData($ch, $data)
    {
        static $buffer = '';
        static $completeContent = '';
        static $messageCount = 0;
        static $totalDataReceived = 0;
        
        $totalDataReceived += strlen($data);
        $buffer .= $data;
        
        // 记录数据接收情况（每5条消息记录一次）
        if ($messageCount % 5 === 0) {
            error_log("豆包API数据接收: 消息数={$messageCount}, 总数据量={$totalDataReceived}字节, 缓冲区大小=" . strlen($buffer));
        }
        
        // 解析SSE数据流
        $lines = explode("\n", $buffer);
        $buffer = array_pop($lines); // 保留最后一行（可能不完整）
        
        foreach ($lines as $line) {
            $line = trim($line);
            
            // 处理SSE数据行
            if (strpos($line, 'data: ') === 0) {
                $json = substr($line, 6);
                
                // 检查流结束标记
                if ($json === '[DONE]') {
                    error_log('豆包API流式结束标记接收');
                    $this->finalizeStream($completeContent);
                    return strlen($data); // 返回数据长度
                }
                
                // 解析JSON数据
                $response = json_decode($json, true);
                if (json_last_error() !== JSON_ERROR_NONE) {
                    error_log('豆包API JSON解析错误: ' . json_last_error_msg() . ', 数据: ' . $json);
                    continue;
                }
                
                // 处理豆包API响应
                if (isset($response['choices'][0]['delta']['content'])) {
                    $content = $response['choices'][0]['delta']['content'];
                    $messageCount++;
                    
                    if (!empty($content)) {
                        // 积累完整内容
                        $completeContent .= $content;
                        // 清理内容
                        $cleanContent = $this->cleanContent($content);
                        if (!empty($cleanContent)) {
                            // 根据流式模式发送内容
                            $this->sendContentByMode($cleanContent);
                        }
                    }
                }
                
                // 处理错误情况
                if (isset($response['error'])) {
                    error_log('豆包API返回错误: ' . json_encode($response['error'], JSON_UNESCAPED_UNICODE));
                    $this->sendEvent('error', '豆包API错误: ' . $response['error']['message']);
                    $this->sendEvent('end', '对话结束');
                    return strlen($data); // 返回数据长度
                }
            }
            
            // 处理其他SSE事件类型
            elseif (strpos($line, 'event: ') === 0) {
                $eventType = trim(substr($line, 7));
                // 可以根据事件类型做特殊处理
            }
        }
        
        // 返回处理的数据长度
        return strlen($data);
    }
    
    /**
     * 根据流式模式发送内容
     */
    private function sendContentByMode($content)
    {
        switch ($this->streamMode) {
            case 'char':
                $this->sendContentCharByChar($content);
                break;
            case 'word':
                $this->sendContentWordByWord($content);
                break;
            case 'chunk':
                $this->sendContentAsChunk($content);
                break;
            case 'complete':
                // complete模式不在这里发送，等待最后一次性发送
                break;
            default:
                $this->sendContentCharByChar($content);
        }
    }
    
    /**
     * 逐词发送内容方法
     */
    private function sendContentWordByWord($content)
    {
        $words = $this->splitContentIntoWords($content);
        
        foreach ($words as $word) {
            if (!empty($word)) {
                $this->sendEvent('content', $word);
                
                // 根据词语类型调整延迟 - 减少延迟以增强流式效果
                if (preg_match('/[\x{4e00}-\x{9fff}]/u', $word)) {
                    usleep(40000); // 中文词 40ms (原来100ms)
                } else {
                    usleep(30000);  // 英文词 30ms (原来80ms)
                }
            }
        }
    }
    
    /**
     * 分块发送内容方法
     */
    private function sendContentAsChunk($content)
    {
        // 直接发送整个块，但有较短延迟
        $this->sendEvent('content', $content);
        usleep(50000); // 50ms (原来200ms)
    }
    
    /**
     * 逐字符发送内容方法
     */
    private function sendContentCharByChar($content)
    {
        // 将内容按字符分割
        $chars = mb_str_split($content, 1, 'UTF-8');
        
        foreach ($chars as $char) {
            // 发送单个字符
            $this->sendEvent('content', $char);
            
            // 根据字符类型调整延迟 - 减少延迟时间以增强流式效果
            if (preg_match('/[\x{4e00}-\x{9fff}]/u', $char)) {
                // 中文字符，延迟稍长
                usleep(30000); // 30ms (原来80ms)
            } elseif (preg_match('/[a-zA-Z0-9]/', $char)) {
                // 英文数字，延迟较短
                usleep(20000); // 20ms (原来50ms)
            } else {
                // 标点符号等，延迟最短
                usleep(10000); // 10ms (原来30ms)
            }
        }
    }
    
    /**
     * 优化的内容发送方法（保留，用于批量发送）
     */
    private function sendOptimizedContent($content)
    {
        // 按词语分割而不是按字符，提高可读性
        $words = $this->splitContentIntoWords($content);
        
        foreach ($words as $word) {
            if (!empty(trim($word))) {
                $this->sendEvent('content', $word);
                
                // 动态调整延迟，根据内容长度
                $delay = min(30000, max(10000, strlen($word) * 2000)); // 10-30ms
                usleep($delay);
            }
        }
    }
    
    /**
     * 智能分割内容为词语
     */
    private function splitContentIntoWords($content)
    {
        // 中文按字符分割，英文按单词分割
        $words = [];
        $currentWord = '';
        
        $chars = mb_str_split($content, 1, 'UTF-8');
        
        foreach ($chars as $char) {
            // 中文字符直接作为一个词
            if (preg_match('/[\x{4e00}-\x{9fff}]/u', $char)) {
                if (!empty($currentWord)) {
                    $words[] = $currentWord;
                    $currentWord = '';
                }
                $words[] = $char;
            }
            // 空格、标点作为分割符
            elseif (preg_match('/[\s\.,;!?]/u', $char)) {
                if (!empty($currentWord)) {
                    $words[] = $currentWord;
                    $currentWord = '';
                }
                $words[] = $char;
            }
            // 英文字符累积
            else {
                $currentWord .= $char;
            }
        }
        
        if (!empty($currentWord)) {
            $words[] = $currentWord;
        }
        
        return $words;
    }
    
    /**
     * 完成流处理（纯文字版本）
     */
    private function finalizeStream($completeContent)
    {
        error_log('开始流完成处理');
        
        if (!empty($completeContent)) {
            try {
                // 如果是complete模式，在这里一次性发送全部内容
                if ($this->streamMode === 'complete') {
                    $cleanCompleteContent = $this->cleanContent($completeContent);
                    $this->sendEvent('content', $cleanCompleteContent);
                }
                
                // 不处理数学公式和格式化，直接返回原文
                $this->sendEvent('processed', $completeContent);
                
                // 发送统计信息
                $stats = [
                    'total_length' => mb_strlen($completeContent, 'UTF-8'),
                    'word_count' => str_word_count($completeContent),  // 不需要strip_tags
                    'processing_time' => microtime(true),
                    'stream_mode' => $this->streamMode
                ];
                
                $this->sendEvent('stats', json_encode($stats));
                
            } catch (\Exception $e) {
                error_log('流处理完成时错误: ' . $e->getMessage());
                $this->sendEvent('processed', $completeContent); // 直接返回原文
            }
        }
        
        // 发送结束事件
        $this->sendEvent('end', '对话结束');
        
        error_log('流完成处理结束');
    }
    
    /**
     * 检测图片类型
     */
    private function detectImageType($image)
    {
        if (empty($image)) {
            return 'none';
        }
        
        if (strpos($image, 'data:') === 0) {
            return 'base64';
        }
        
        if (filter_var($image, FILTER_VALIDATE_URL)) {
            return 'url';
        }
        
        return 'unknown';
    }
    
    /**
     * 获取HTTP错误消息
     */
    private function getHttpErrorMessage($httpCode)
    {
        $errorMessages = [
            400 => '请求参数错误',
            401 => 'API密钥无效或过期',
            403 => '没有访问权限',
            404 => 'API地址不存在',
            429 => '请求过于频繁，请稍后再试',
            500 => '服务器内部错误',
            502 => '网关错误',
            503 => '服务不可用',
            504 => '网关超时'
        ];
        
        return $errorMessages[$httpCode] ?? '未知HTTP错误';
    }
    
    /**
     * 清理内容，移除特殊字符（不处理格式化标记）
     */
    private function cleanContent($content)
    {
        // 移除一些常见的特殊字符
        $specialChars = [
            '\u0000', '\u0001', '\u0002', '\u0003', '\u0004', '\u0005',
            '\u0006', '\u0007', '\u0008', '\u000b', '\u000c', '\u000e',
            '\u000f', '\u0010', '\u0011', '\u0012', '\u0013', '\u0014',
            '\u0015', '\u0016', '\u0017', '\u0018', '\u0019', '\u001a',
            '\u001b', '\u001c', '\u001d', '\u001e', '\u001f'
        ];
        
        foreach ($specialChars as $char) {
            $content = str_replace($char, '', $content);
        }
        
        // 移除不可打印字符
        $content = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $content);
        
        // 不处理Markdown格式化标记，直接返回原文
        
        return $content;
    }
    
    /**
     * 处理Markdown格式化标记（豆包格式）
     */
    private function processMarkdownFormat($content)
    {
        // 处理标题标记
        $content = preg_replace('/^### (.+)$/m', '<h3 style="color: #333; font-weight: bold; margin: 1em 0 0.5em 0; font-size: 1.2em;">$1</h3>', $content);
        $content = preg_replace('/^## (.+)$/m', '<h2 style="color: #333; font-weight: bold; margin: 1em 0 0.5em 0; font-size: 1.3em;">$1</h2>', $content);
        $content = preg_replace('/^# (.+)$/m', '<h1 style="color: #333; font-weight: bold; margin: 1em 0 0.5em 0; font-size: 1.4em;">$1</h1>', $content);
        
        // 处理粗体标记
        $content = preg_replace('/\*\*(.+?)\*\*/', '<strong style="font-weight: bold;">$1</strong>', $content);
        
        // 处理斜体标记
        $content = preg_replace('/\*(.+?)\*/', '<em style="font-style: italic;">$1</em>', $content);
        
        // 处理行内代码
        $content = preg_replace('/`(.+?)`/', '<code style="background: #f5f5f5; padding: 2px 4px; border-radius: 3px; font-family: monospace;">$1</code>', $content);
        
        // 处理代码块标记
        $content = preg_replace('/```([\s\S]*?)```/', '<pre style="background: #f5f5f5; padding: 10px; border-radius: 5px; overflow-x: auto; white-space: pre-wrap;"><code>$1</code></pre>', $content);
        
        // 处理无序列表
        $content = preg_replace('/^[-*+] (.+)$/m', '<li style="margin: 0.2em 0;">$1</li>', $content);
        
        // 处理有序列表
        $content = preg_replace('/^\d+\. (.+)$/m', '<li style="margin: 0.2em 0;">$1</li>', $content);
        
        // 包装连续的<li>为<ul>或<ol>
        $content = preg_replace('/((?:<li[^>]*>.*?<\/li>\s*)+)/', '<ul style="margin: 0.5em 0; padding-left: 1.5em;">$1</ul>', $content);
        
        // 处理分割线
        $content = preg_replace('/^---+$/m', '<hr style="border: none; border-top: 1px solid #ddd; margin: 1em 0;">', $content);
        
        // 处理换行
        $content = preg_replace('/\n\n+/', '</p><p style="margin: 0.8em 0; line-height: 1.6;">', $content);
        
        // 添加段落包装
        if (!empty(trim($content))) {
            $content = '<p style="margin: 0.8em 0; line-height: 1.6;">' . $content . '</p>';
        }
        
        return $content;
    }
    
    /**
     * 处理数学公式和格式化标记
     */
    private function processFormulas($content)
    {
        // 先处理Markdown格式化标记
        $content = $this->processMarkdownFormat($content);
        
        // 再处理数学公式
        $content = \app\common\library\MathFormulaProcessor::processFormulas($content);
        
        return $content;
    }
    
    /**
     * 处理图片
     */
    private function processImage($image)
    {
        
        if (filter_var($image, FILTER_VALIDATE_URL)) {
            try {
                $content = file_get_contents($image);
                
                $mime = (new \finfo(FILEINFO_MIME_TYPE))->buffer($content);
               
                return 'data:' . $mime . ';base64,' . base64_encode($content);
            } catch (\Exception $e) {
                return $image;
            }
        }
        
        return strpos($image, 'data:') === 0 ? $image : 'data:image/jpeg;base64,' . $image;
    }
    
    /**
     * 发送SSE事件 - 针对Nginx + PHP-FPM环境优化
     */
    private function sendEvent($event, $data)
    {
        // 构建 SSE 数据格式
        $message = "event: $event\n";
        $message .= "data: " . json_encode(['content' => $data], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n\n";
        
        // 直接输出数据
        echo $message;
        
        // 确保数据发送
        if (ob_get_level() > 0) {
            ob_flush();
        }
        flush();
        
        // 注意：不要在每次发送事件时调用 fastcgi_finish_request()
        // 这会导致连接提前断开
        
        // 记录发送的数据（仅在调试时）
        static $sentCount = 0;
        $sentCount++;
        if ($sentCount % 20 === 1) { // 每20条记录一次
            error_log("已发送SSE事件: {$event}, 数据长度: " . mb_strlen($data, 'UTF-8') . ", 总数: {$sentCount}");
        }
    }
    
    /**
     * 发送错误并结束 - 针对Nginx + PHP-FPM环境优化
     */
    private function streamError($message)
    {
        // 设置优化的响应头
        $this->setOptimizedHeaders();
        
        echo "event: error\n";
        echo "data: " . json_encode(['content' => $message], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n\n";
        echo "event: end\n";
        echo "data: " . json_encode(['content' => '连接结束'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n\n";
        
        // 确保数据发送
        flush();
        
        // 在错误处理结束时可以调用 fastcgi_finish_request()
        if (function_exists('fastcgi_finish_request')) {
            fastcgi_finish_request();
        }
        
        exit;
    }
}